package app.Insam.VNC;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.util.Log;

import java.util.List;
import java.util.ListIterator;

public class InsamWifiManager {
	public static final String TAG = "InsamWifiManager";
	static protected boolean mWifiOff=false;
	
	
	protected InsamService mParent;
	protected InsamScheduler mScheduler;
	
	protected WifiManager mWifi;
	protected int mScanFault_cnt=0;
	protected boolean mScanning=false;			
	
	protected Thread mFaultHandlerThread;
	BroadcastReceiver mReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context _context, Intent _intent) {
			if(_intent==null) return;
			if(_intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
				List<ScanResult> resultList = mWifi.getScanResults();				
				off();				
				
				if(resultList==null || resultList.size()==0) {
					Log.d(TAG, "No available AP");
					wifiFaultHandler();
					return;
				}
				
//				InsamDebugger.toast(TAG, "receive ssid list:"+resultList.size());
				mScanning=false;				
				mScanFault_cnt=0;	
				ListIterator<ScanResult> result = resultList.listIterator();	
				boolean inOffice = false;
				ScanResult info;
				while(result.hasNext()) {
					info = result.next();
					//InsamDebugger.toast(TAG, info.SSID+":"+info.level);
					if(info.SSID.contains(InsamApp.OfficeSSID)) {
						inOffice = true;
						Log.d(TAG, "detect office network!!");
						break;
					}				
				}
				if(inOffice == true) {
					if(InsamApp.InOffice == false) {
						mParent.inOffice();
					}
					int delay = (mWifiOff ? InsamApp.TIME_RESCAN_IN_OFFICE/2 : InsamApp.TIME_RESCAN_IN_OFFICE);
					mScheduler.schedule(InsamService.ACTION_SCAN_WIFI, delay);
				} else {				
					if(InsamApp.InOffice == true) {
						mParent.outOffice();
						mScheduler.schedule(InsamService.ACTION_SCAN_WIFI, InsamApp.TIME_RESCAN_MINIMUM);
					} else {
						Log.d(TAG, "can't find office network");
						mScheduler.schedule(InsamService.ACTION_SCAN_LOCATION, InsamApp.TIME_RESCAN_MINIMUM);
					}
				}
				Log.v(TAG, "checking wifi end");				
			} else if(_intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {					
				switch(mWifi.getWifiState()) {				
				case WifiManager.WIFI_STATE_DISABLED:		
					Log.v(TAG, "wifi off");			
					if(mWifiOff==true) {
						mWifiOff=false;
					} else {
						Log.v(TAG, "detect to change wifi state turn off");
						checkWifi();							
					}
					break;
				case WifiManager.WIFI_STATE_ENABLED:	
					Log.v(TAG, "wifi on");
					break;
				}
			}
		}	
	};

	public InsamWifiManager(InsamService _Parent, InsamScheduler _scheduler) {
		mParent = _Parent;
		mScheduler = _scheduler;
		mWifi = (WifiManager)mParent.getSystemService(Context.WIFI_SERVICE);		
		mParent.registerReceiver(mReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
		mParent.registerReceiver(mReceiver, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
	}
	
	public void checkWifi() {
		if(InsamApp.OfficeSSID==null) {
			mParent.stopSelf();
			return;
		}
		Log.v(TAG, "checking wifi");
		mScanning=true;
		mFaultHandlerThread = new Thread() {		//if no response during 1min, call handler.
			@Override
			public void run() {
				try {
					sleep(1000*60);
					if(mScanning) {
						Log.w(TAG, "Can't scan wifi");
						wifiFaultHandler();
					}
				} 				
				catch (InterruptedException e) {
					Log.d(TAG, "Cancel fault handler thread");
				}
			}			
		};
		mFaultHandlerThread.start();
		
		if(mWifi.isWifiEnabled()) {	
			String SSID = mWifi.getConnectionInfo().getSSID();
			if(SSID==null) {
				Log.w(TAG, "receive null ssid");
				wifiFaultHandler();
			} else if(SSID.equals(InsamApp.OfficeSSID)) {				
				Log.v(TAG, "already connected");
				
				if(InsamApp.InOffice == false) {
					Log.w(TAG, "connected already but catch now.");
					mParent.inOffice();
				}
				mScheduler.schedule(InsamService.ACTION_SCAN_WIFI, InsamApp.TIME_RESCAN_IN_OFFICE);
				mScanning=false;
			} else {
				mWifi.startScan();
			}			
		} else {
			on();
		}
	}
	
	public void wifiFaultHandler() {
		++mScanFault_cnt;
		Log.d(TAG, "Wifi fault Handler:" + mScanFault_cnt);
		
		mScanning=false;
		if(mScanFault_cnt>2) {			//3번 이상 접속가능한 ap가 없을 경우 wifi를 강제로 끔						
			Log.i(TAG, "handler force wifi off");
			mWifiOff=true;
			off();
			if(mScheduler.isIdle()) {
				mScheduler.schedule(InsamService.ACTION_SCAN_LOCATION, InsamApp.TIME_RESCAN_MINIMUM);
			}
			mScanFault_cnt=0;
			return;
		}
		
		off();		
		if(mScheduler.isIdle()) {
			mScheduler.schedule(InsamService.ACTION_SCAN_WIFI, InsamApp.TIME_RESCAN_MINIMUM/2);
		}
	}
	
	public void stop() {
		Log.d(TAG, "stop WifiManager");
		mParent.unregisterReceiver(mReceiver);
		if(mFaultHandlerThread!=null && mFaultHandlerThread.isAlive()) {
			mFaultHandlerThread.interrupt();
		}
		off();
	}
	
	public void on() {			
		mWifi.setWifiEnabled(true);
		mWifiOff=true;		
	}
	
	public void off() {
		if(mWifiOff==true) {
			mWifi.setWifiEnabled(false);
		}
	}
}
